package com.freecsim.sas.kernel;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Logger;

class ShutdownHandler implements Runnable{
	
	private static final Logger logger = Logger.getLogger(ShutdownHandler.class.getName());
	/*
	 * 关闭监听Socket
	 */
	private final ServerSocket listen;
	
	/*
	 * socket连接监听列表
	 */
	private final Set<SocketListener> currentListeners;

	private Kernel kernel;
	
	/**
	 * 完成关闭
	 */
	private boolean completeClose;
	
	/**
	 * 关闭命令
	 */
	private String shutdownCommand = "SHUTDOWN";
	
	private Thread shutdownHookThread;
	
	private Thread socketListenerThread;
	/**
	 * 构造方法
	 * @param port 监听端口
	 * @throws IOException 
	 */
	public ShutdownHandler(Kernel kernel, int port, String shutdownCommand) throws IOException{
		this.currentListeners = new HashSet<SocketListener>();
		this.kernel = kernel;
		try {
			if(shutdownCommand != null && !shutdownCommand.trim().equals("")){
				this.shutdownCommand = shutdownCommand.trim();
			}
			this.listen = new ServerSocket(port, -1, InetAddress.getByName(null));
		} catch (IOException e) {
			logger.error("Unable to listen on port : " + port, e);
			throw e;
		}
		
		shutdownHookThread = new Thread("shutdownHook") {
			public void run() {
				if(!completeClose){
					ShutdownHandler.this.shutdown();
				}
				System.out.println("Thread [" + Thread.currentThread().getName() +"] is stoped.");
			}
		};
		Runtime.getRuntime().addShutdownHook(shutdownHookThread);
	}
	
	/**
	 * 关闭程序
	 */
	public synchronized void shutdown(){
		if(!completeClose){
			new Thread(new Runnable() {
				@Override
				public void run() {
					logger.info("Server is shutdown...");
					kernel.quit();
					close();
					if(shutdownHookThread != null && shutdownHookThread.isAlive()){
						shutdownHookThread.interrupt();
					}
					
					if(socketListenerThread != null && socketListenerThread.isAlive()){
						socketListenerThread.interrupt();
					}
					completeClose = true;
					System.exit(0);
				}
			}).start();
		}
	}
	
	synchronized void close(){
		if (!(this.listen.isClosed())) {
			close(this.listen);
		}
		for (SocketListener connection : this.currentListeners) {
			connection.close();
		}
		this.currentListeners.clear();
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run(){
		while(!completeClose){
			try{
				Socket incoming = this.listen.accept();
				SocketListener handle = new SocketListener(incoming);
				currentListeners.add(handle);
				socketListenerThread = new Thread(handle,"close thread");
				socketListenerThread.start();
			} catch (Exception e) {
				//logger.error("Shutdown socket server closed", e);
				close(this.listen);
			}
		}
	}

	private static void close(Closeable c){
		try{
			c.close();
		} catch (IOException ignore) {
			logger.error("Error closing object", ignore);
		}
	}

	private static void close(Socket s){
		try{
			s.close();
		} catch (IOException ignore) {
			logger.error("Error closing object", ignore);
		}
	}

	private static void close(ServerSocket s){
		try
		{
			s.close();
		} catch (IOException ignore) {
			logger.error("Error closing object", ignore);
		}
	}

	/**
	 * Socket监听线程
	 * @author GeorgeWu
	 *
	 */
	private class SocketListener implements Runnable{
		private Socket socket;

		/**
		 * 构造方法
		 * @param paramSocket
		 */
		public SocketListener(Socket paramSocket){
			this.socket = paramSocket;
		}

		/*
		 * (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		public void run(){
			BufferedReader in = null;
			try {
				in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
				String inputLine = "";
				do{
					if ((inputLine = in.readLine()) == null){ 
						break;
					};
				}
				while (!(inputLine.equals(shutdownCommand)));
				ShutdownHandler.this.shutdown();
			}catch (IOException e){
				logger.error("Shutdown socket closed", e);
			}finally {
				ShutdownHandler.this.currentListeners.remove(this);
				ShutdownHandler.close(in);
				ShutdownHandler.close(this.socket);
			}
		}

		/**
		 * 关闭释放的socket资源
		 */
		public void close(){
			ShutdownHandler.close(this.socket);
		}
	}
}